Iggy
Getting Started with Apache Iggy: A Beginner's Guide
Apache Iggy is a high-performance message streaming platform. Think of it as a super-fast post office. You have:
- Producers: Applications that send messages (letters).
- Consumers: Applications that receive messages.
- Streams: Mailboxes for different categories of messages.
- Topics: Sub-categories within a stream (like "invoices" or "notifications").
- Partitions: Ways to split topics for even faster processing.
Here’s how you can get started:
Step 1: Run the Iggy Server
The easiest way to start is by using Docker. This avoids building the project from the source code.
- Install Docker: If you don't have it, download and install Docker Desktop.
- Pull the Iggy image: Open your terminal and run:
docker pull apache/iggy - Run the Iggy server:
This command starts the Iggy server in the background. It will be accessible on your machine at
docker run -d -p 8090:8090 -p 8080:8080 apache/iggy127.0.0.1:8090.
Step 2: Set Up Your Rust Project
You'll need Rust installed. If you don't have it, go to rust-lang.org.
-
Create a new project:
cargo new iggy-example
cd iggy-example -
Add dependencies: You'll need
iggyfor the client andtokiofor asynchronous operations.cargo add iggy
cargo add tokio --features full
cargo add tracing tracing-subscriber -
Project Structure: The "Getting Started" guide recommends creating separate files for the producer and consumer.
- Create
src/producer.rsandsrc/consumer.rs. - Update
Cargo.tomlto define two separate binaries:
[[bin]]
name = "producer"
path = "src/producer.rs"
[[bin]]
name = "consumer"
path = "src/consumer.rs" - Create
Step 3: Build the Producer
This application will send a message. Create the file src/producer.rs with the following code:
use iggy::client::Client;
use iggy::clients::client::IggyClient;
use iggy::messages::send_messages::{Message, SendMessages};
use iggy::models::header::{HeaderKey, HeaderValue};
use iggy::streams::create_stream::CreateStream;
use iggy::topics::create_topic::CreateTopic;
use iggy::users::defaults::{DEFAULT_ROOT_PASSWORD, DEFAULT_ROOT_USERNAME};
use std::collections::HashMap;
use std::error::Error;
use std::sync::Arc;
use tracing::info;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
tracing_subscriber::fmt::init();
let client = IggyClient::default();
client.connect().await?;
client
.login_user(DEFAULT_ROOT_USERNAME, DEFAULT_ROOT_PASSWORD)
.await?;
let stream_id = 1;
client
.create_stream(&CreateStream {
stream_id: Some(stream_id),
name: "sample-stream".to_string(),
})
.await?;
info!("Created stream with ID: {}", stream_id);
let topic_id = 1;
client
.create_topic(&CreateTopic {
stream_id: stream_id.try_into()?,
topic_id: Some(topic_id),
partitions_count: 1,
name: "sample-topic".to_string(),
})
.await?;
info!("Created topic with ID: {}", topic_id);
let mut messages = Vec::new();
let mut headers = HashMap::new();
headers.insert(
HeaderKey::new("key").unwrap(),
HeaderValue::from_str("value").unwrap(),
);
let message = Message {
id: 1,
length: 13,
payload: Arc::new("Hello, Iggy!".as_bytes().to_vec()),
headers: Some(headers),
};
messages.push(message);
client
.send_messages(&mut SendMessages {
stream_id: stream_id.try_into()?,
topic_id: topic_id.try_into()?,
partitioning: 0.try_into()?,
messages,
})
.await?;
info!("Sent message: 'Hello, Iggy!'");
client.disconnect().await?;
Ok(())
}
Step 4: Build the Consumer
This application will receive the message. Create the file src/consumer.rs with the following code:
use iggy::client::Client;
use iggy::clients::client::IggyClient;
use iggy::messages::poll_messages::{PollMessages, PollingStrategy};
use iggy::models::consumer::{Consumer, ConsumerKind};
use iggy::users::defaults::{DEFAULT_ROOT_PASSWORD, DEFAULT_ROOT_USERNAME};
use std::error::Error;
use std::time::Duration;
use tokio::time::sleep;
use tracing::info;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
tracing_subscriber::fmt::init();
let client = IggyClient::default();
client.connect().await?;
client
.login_user(DEFAULT_ROOT_USERNAME, DEFAULT_ROOT_PASSWORD)
.await?;
let stream_id = 1;
let topic_id = 1;
let partition_id = 1;
let consumer = Consumer {
kind: ConsumerKind::Consumer,
id: 1,
};
loop {
let messages = client
.poll_messages(&PollMessages {
consumer: consumer.clone(),
stream_id: stream_id.try_into()?,
topic_id: topic_id.try_into()?,
partition_id: Some(partition_id),
strategy: PollingStrategy::offset(0),
count: 1,
auto_commit: true,
})
.await?;
if messages.messages.is_empty() {
info!("No messages found");
sleep(Duration::from_secs(1)).await;
continue;
}
for message in messages.messages {
info!(
"Received message: {}",
String::from_utf8(message.payload.to_vec())?
);
}
}
}
Step 5: Run Your Applications
-
Run the consumer: In one terminal, run:
cargo run --bin consumerIt will start and wait for messages.
-
Run the producer: In another terminal, run:
cargo run --bin producerThis will send the message "Hello, Iggy!". You should see the consumer terminal print that it has received the message.
Summary
You have now:
- Started an Apache Iggy server.
- Created a Rust project with a producer and a consumer.
- Sent a message from the producer.
- Received the message in the consumer.
This is the foundation of message streaming. From here, you can explore more advanced topics like consumer groups, different data types, and error handling.